﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using GigaSite.Domain.Entities;
using GigaSite.Domain.Infrastucture.Geocoder;
using GigaSite.Domain.Interfaces.Infrastructure;
using GigaSite.Domain.Interfaces.Repositories;
using GigaSite.Domain.IoC;
using GigaSite.Web.Areas.ControlPanel.Exceptions;
using GigaSite.Web.Areas.ControlPanel.Models;

namespace GigaSite.Web.Areas.ControlPanel.Controllers
{
    /// <summary>
    /// Контроллер управления торговыми центрами
    /// </summary>
    public class ManageShoppingMallsController : BaseRootController
    {
        //
        // GET: /ControlPanel/ManageShoppingMalls/
        /// <summary>
        /// Отображает корневую вкладку управления
        /// </summary>
        /// <returns></returns>
        public ActionResult Index()
        {
            return View();
        }

        /// <summary>
        /// Загружает сведения о торговых центрах на клиент
        /// </summary>
        /// <returns>Все торговые центры системы в виде JSON</returns>
        [HttpPost]
        public JsonResult GetShoppingMalls()
        {
            try
            {
                // Получаем репозиторий
                var repository = Locator.GetService<IShoppingMallsRepository>();

                // получаем все торговые центры
                var malls = repository.FindAll().AsEnumerable().Select(m => new ShoppingMallModel(m));

                // Отдаем их
                return JsonSuccess(malls);
            }
            catch (Exception e)
            {
                return JsonErrors(e);
            }
        }

        /// <summary>
        /// Сохраняет изменения в существующем торговом центре или создает новый
        /// </summary>
        /// <returns></returns>
        public JsonResult Save(long id,string systemName,string displayName,string description,string city,string address,double latitude,double longitude)
        {
            try
            {
                // Репозиторий
                var repository = Locator.GetService<IShoppingMallsRepository>();

                if (id < 0)
                {
                    // Проверяем что в системе нет торговых центров с таким же именем
                    if (repository.Find(m => m.SystemName == systemName) != null)
                    {
                        throw new ShoppingMallExistsException(systemName);
                    }

                    // Создаем новый торговый центр
                    var shoppingMall = new ShoppingMall()
                                           {
                                               Address = address,
                                               DisplayName = displayName,
                                               SystemName = systemName,
                                               CityId = 1, // NOTE: поддерживается только Хабаровск
                                               DateCreated = DateTime.Now,
                                               Description = description,
                                               Latitude = latitude,
                                               Longitude = longitude,
                                               Views = 0
                                           };
                    repository.Add(shoppingMall);
                }
                else
                {
                    // Идет редактирование торгового центра
                    var shoppingMall = repository.Load(id);
                    if (shoppingMall == null)
                    {
                        throw new ObjectNotFoundException(String.Format("Торговый центр с идентификатором {0} не найден",id));
                    }

                    // Проверяем что нет такого же системного имени
                    if (systemName != shoppingMall.SystemName && repository.Find(m => m.SystemName == systemName) != null)
                    {
                        throw new ShoppingMallExistsException(systemName);    
                    }

                    shoppingMall.DisplayName = displayName;
                    shoppingMall.SystemName = systemName;
                    shoppingMall.Description = description;
                    shoppingMall.Address = address;
                    shoppingMall.Latitude = latitude;
                    shoppingMall.Longitude = longitude;
                    shoppingMall.DateModified = DateTime.Now;
                }

                // В любом случае, сабмитим изменения
                repository.SubmitChanges();

                return JsonSuccess();
            }
            catch (Exception e)
            {
                return JsonErrors(e);
            }
        }

        /// <summary>
        /// Удаляет выбранный торговый центр и все его связи из системы
        /// </summary>
        /// <param name="id">Идентификатор торгового центра</param>
        /// <returns>Сообщение о результате выполнения операции</returns>
        [HttpPost]
        public JsonResult Delete(long id)
        {
            try
            {
                // Репозиторий
                var repository = Locator.GetService<IShoppingMallsRepository>();

                // Ищем торговый центр
                var mall = repository.Load(id);
                if (mall == null)
                {
                    throw new ObjectNotFoundException(String.Format("Торговый центр с идентификатором {0} не найден", id));
                }

                // Удаляем
                repository.Delete(mall);
                repository.SubmitChanges();

                //Возвращаем результат
                return JsonSuccess();
            }
            catch (Exception e)
            {
                return JsonErrors(e);
            }
        }

        /// <summary>
        /// Возвращает на клиент данные о организациях, зарегистрированных в торговом центре
        /// </summary>
        /// <returns>Коллекция ссылок на организации в Json формате</returns>
        [HttpPost]
        public JsonResult GetShoppingMallOrganizations(long id)
        {
            try
            {
                var repository = Locator.GetService<IShoppingMallsRepository>();

                // Загружаем
                var shoppingMall = repository.Load(id);
                if (shoppingMall == null)
                {
                    throw new ObjectNotFoundException(String.Format("Торговый центр с идентификатором {0} не найден",id));
                }

                // Преобразуем маппинги
                var links = repository.GetOrganizationsInShoppingMall(shoppingMall).Select(m => new
                                                                                            {
                                                                                               organizationId = m.Id,
                                                                                               displayName = m.DisplayName
                                                                                            });
                // Отправляем результат
                return JsonSuccess(links);
            }
            catch (Exception e)
            {
                return JsonErrors(e);
            }
        }

        /// <summary>
        /// Возвращает на клиент данные о фотографиях, прикрепленных к торговому центру
        /// </summary>
        /// <param name="id">Идентификатор торгового центра</param>
        /// <returns></returns>
        [HttpPost]
        public JsonResult GetShoppingMallPhotos(long id)
        {
            throw new NotImplementedException("Еще не запилено");
        }

        /// <summary>
        /// Запускает геокодирование торговых центров, геокодируются только те центры, которые не имеют координат
        /// </summary>
        /// <returns>Данные о геокодировании в формате Json</returns>
        [HttpPost]
        public JsonResult GeocodeShoppingMalls()
        {
            try
            {
                // Репозитории и менеджеыр
                var repository = Locator.GetService<IShoppingMallsRepository>();
                var geocoder = Locator.GetService<IGeocoder>();

                // Получаем негеокодированные торговые центры
                var ungeocoded = repository.GetUngeocodedShoppingMalls();
                long total = 0, geocoded = 0;

                // Запускаем процедуру
                
                foreach (var shoppingMall in ungeocoded)
                {
                    total++;
                    var result = geocoder.Geocode(shoppingMall);
                    if (result.Successfull)
                    {
                        // Нашил координаты
                        geocoded++;
                        shoppingMall.Latitude = result.Latitude;
                        shoppingMall.Longitude = result.Longitude;
                    }
                    else
                    {
                        // Не нашли
                        // TODO: сделать запись в лог
                    }
                }

                // Сохраняем результаты геокодирования
                repository.SubmitChanges();

                // Отправляем результаты
                return JsonSuccess(new
                                       {
                                           total,
                                           geocoded
                                       });
            }
            catch (Exception e)
            {
                return JsonErrors(e);
            }
        }

        /// <summary>
        /// Геокодирует указанный адрес в указанном городе и возвращает результат на клиент
        /// </summary>
        /// <param name="city">Город</param>
        /// <param name="address">Адрес в городе</param>
        /// <returns>Результаты геокодирования</returns>
        [HttpPost]
        public JsonResult GeocodeAddress(string city, string address)
        {
            try
            {
                // Получаем геокодер
                var geocoder = Locator.GetService<IGeocoder>();

                // Пытаемся геокодировать
                var result = geocoder.Geocode(String.Format("{0} {1}", city, address));

                if (result.Successfull)
                {
                    // Отправляем результат геокодирования
                    return JsonSuccess(new
                                           {
                                               latitude = result.Latitude,
                                               longitude = result.Longitude
                                           });
                }
                else
                {
                    throw new GeocoderException(string.Format("Не удалось получить GPS координаты для адреса {0} {1}", city,
                                                              address));
                }
            }
            catch (Exception e)
            {
                return JsonErrors(e);
            }
        }
    }
}
